/*
*
* FILENAME:		linear_slk.c/linear_slk.h 
* CREATED AT:		2012/May/15
* DECRITION:		implement the linear in the form of single linker
* 
* MODULE:		linead list
* PLATFORM:		ubuntu-12.04/gcc-4.6.3
* AUTHOR:		incarnation-lee
* 
* ----------------------REVISION HISTROY------------------------
* No.	Date	Revised by	Function			Descrition
* 1	12/5/15	incar-lee	demo,init,destory,isEmpty,	implement the feature
				clear,len and add
  2	12/5/16	incar-lee	get,next and prior		implement the feature
  3	12/5/19	incar-lee	insert, delete			implement the feature
  4	12/5/30	incar-lee	destory				fix a bug of rask of memory leak
  5	12/5/30 incar-lee	clear				fix a bug of free a local no pointer variable
*
*/

/* Standard C */
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

/* linux related */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

/* user defined */
#include "externals.h"
#include "udgtd.h"
#include "linear_slk.h"
#include "errcode.h"


/**************************************
* operation functions on data element *
***************************************/

/*
* initilize the single linker linear
*/
static STATUS init_slnk(S_slk_lr** slk_lr_head)
{
	gmalloc((void**)slk_lr_head,sizeof(S_slk_lr));
	if(__builtin_expect(!!(slk_lr_head==NULL),0))
		return -1;
	(*slk_lr_head)->elem = NULL;
	(*slk_lr_head)->next = NULL;
	return 0;
}

/*
* destory single linker linear
*/
static STATUS destory_slnk(S_slk_lr** slk_lr_head)
{
	if(NULL==*slk_lr_head)
	{
		set_errcode(NoEXIT);
		return -1;
	}
	if(NULL!=(*slk_lr_head)->next)			/* for call destory before clear */
	{
		clear_slnk(slk_lr_head);
	}
	free(*slk_lr_head);
	*slk_lr_head = NULL;
	return 0;		

}

/*
* clear all the element of linear list 
*/
static STATUS clear_slnk(S_slk_lr** slk_lr_head)
{
	S_slk_lr *sll_tmp,*slk_N;
	sll_tmp = (*slk_lr_head)->next;
	if(NULL==sll_tmp)
	{
		set_errcode(NoEXIT);
		return -1;
	}

	while(NULL!=sll_tmp)
	{
		free(sll_tmp->elem); 		/* free the memory */
		slk_N = sll_tmp->next;		/* store the next */
		sll_tmp->next = NULL;		/* put the current next to NULL */
		sll_tmp = slk_N;		
	}
	(*slk_lr_head)->next = NULL;
	return 0;		
}

/* 
* linear list is empty 
*/
static STATUS isEmpty_slnk(S_slk_lr* slk_lr_head)
{
	if(NULL==slk_lr_head->next)
		return 0;
	return -1;
}

/*
* the number of linear list 
*/
static size_t len_slnk(S_slk_lr* slk_lr_head)
{
	size_t len = 0;
	assert(NULL!=slk_lr_head);

	if(NULL==slk_lr_head->next)
		return 0;
	slk_lr_head = slk_lr_head->next;
	while(NULL!=slk_lr_head)
	{
		len++;
		slk_lr_head = slk_lr_head->next;
	}
	return len;
}

/* 
* add a new element append the single linker linear list 
*/
static STATUS add_slnk(S_slk_lr* slk_lr_head,S_slk_lr* element)
{
	assert(NULL!=slk_lr_head);
	assert(NULL!=element);

	while(NULL!=slk_lr_head->next)			/* get the last element */
	{
		slk_lr_head = slk_lr_head->next;
	}		
	slk_lr_head->next = element;
	return 0;
	
}

/* 
* get the element of specify element in linear list 
*/
static S_slk_lr* get_slnk(S_slk_lr* slk_lr_head,const S_slk_lr* element)	
{
	assert(NULL!=slk_lr_head);	
	assert(NULL!=element);	
	
	slk_lr_head = slk_lr_head->next;		/* first element */
	while(NULL!=slk_lr_head)
	{
		if( slk_lr_head->elem->value == element->elem->value &&
			slk_lr_head->elem->number == element->elem->number &&
			slk_lr_head->elem->name == element->elem->name)
			return slk_lr_head;	
		slk_lr_head = slk_lr_head->next;
	}
	set_errcode(NoEXIT);
	return NULL;
}

/* 
* the next element 
*/
static S_slk_lr* next_slnk(S_slk_lr* slk_lr_head,const S_slk_lr* element)
{
	S_slk_lr *slk_lr_tmp;
	assert(NULL!=slk_lr_head);	
	assert(NULL!=element);	

	slk_lr_tmp = get_slnk(slk_lr_head,element);

	if(NULL==slk_lr_tmp)
	{
		set_errcode(INVALIDINDEX);
		return NULL;
	}
	return slk_lr_tmp->next;
}			

/* 
* the prior element
*/
static S_slk_lr* prior_slnk(S_slk_lr* slk_lr_head,const S_slk_lr* element)
{
	S_slk_lr *slk_prior;
	assert(NULL!=element);	
	assert(NULL!=slk_lr_head);	

	slk_prior = slk_lr_head;
	slk_lr_head = slk_lr_head->next;		/* first element */
	while(NULL!=slk_lr_head)
	{
		if( slk_lr_head->elem->value == element->elem->value &&
			slk_lr_head->elem->number == element->elem->number &&
			slk_lr_head->elem->name == element->elem->name)
			return slk_prior;	
		slk_prior = slk_lr_head;
		slk_lr_head = slk_lr_head->next;
	}
	set_errcode(INVALIDINDEX);
	return NULL;
}

/* 
* insert a data element 
*/
static STATUS insert_slnk(S_slk_lr* slk_lr_head,S_slk_lr* element,S_slk_lr* dest)
{
	S_slk_lr *slk_tmp,*slk_dest;
	assert(NULL!=element);
	assert(NULL!=slk_lr_head);

	slk_dest = get_slnk(slk_lr_head,dest);	/* location the destination, this why get return pointer */
	if(NULL==slk_dest)
		return -1;

	slk_tmp = slk_dest->next;
	slk_dest->next = element;
	element->next = slk_tmp;

	return 0;	
}

/* 
* delete a data element
*/
static STATUS delete_slnk(S_slk_lr* slk_lr_head,S_slk_lr* element)
{
	S_slk_lr *slk_pri;
	assert(NULL!=slk_lr_head);
	assert(NULL!=element);
	
	slk_pri = prior_slnk(slk_lr_head,element);
	if(NULL==slk_pri)
		return -1;
	slk_pri->next = element->next;
	return 0;
}

